/*
 *  dna_utils.h -- provide dna-system utils interface.
 *  
 *  ORIGINAL AUTHOR: Xu Chun (chun.xu@broadlink.com.cn)
 *
 *  Copyright (c) 2016 Broadlink Corporation
 */

#ifndef __DNA_UTILS_H
#define __DNA_UTILS_H

/**
 * Convert a given hex string to a equivalent binary representation.
 *
 * E.g. If your input string of 4 bytes is {'F', 'F', 'F', 'F'} the output
 * string will be of 2 bytes {255, 255} or to put the same in other way
 * {0xFF, 0xFF}
 *
 * Note that hex2bin is not the same as strtoul as the latter will properly
 * return the integer in the correct machine binary format viz. little
 * endian. hex2bin however does only in-place like replacement of two ASCII
 * characters to one binary number taking 1 byte in memory.
 *
 * @param[in] ibuf input buffer
 * @param[out] obuf output buffer
 * @param[in]  max_olen Maximum output buffer length
 *
 * @return length of the binary string
 */
unsigned int dna_hex2bin(const unsigned char * ibuf, unsigned char * obuf,
		        unsigned max_olen);

/**
 * Convert given binary array to equivalent hex representation.
 *
 * @param[in] src Input buffer
 * @param[out]  dest Output buffer
 * @param[in] src_len Length of the input buffer
 * @param[in] dest_len Length of the output buffer
 *
 * @return length of the hex string
 */
int dna_bin2hex(const unsigned char * src, char * dest, unsigned int src_len,
	     unsigned int dest_len);

void dna_hexdump(const void *data, size_t size, const char *str, ...);

/** Base64 Decode string
 *
 * This function decodes the given Base64 encoded string into raw binary data.
 *
 * \note This function an do in-place decoding. So, the same buffer can be used
 * for input as well as output.
 *
 * \param[in] in Pointer to Base64 encoded string.
 * \param[in] inlen Length of the Base64 encoded string.
 * \param[out] out Pointer to the output buffer that will be populated by the
 * function.
 * \param[in,out] outlen Holds the length of the output buffer and is populated
 * with the length of the decoded data by this function.
 *
 * \return -1 on failure
 * \return 0 on success
 */
int dna_base64decode(const char * in, int inlen, unsigned char * out, int * outlen);

/** Base64 Encode data
 *
 * This function encodes the given raw binary data into a Base64 encoded string.
 *
 * \param[in] in Pointer to raw binary data
 * \param[in] inlen Length if the binary data (in bytes)
 * \param[out] out Pointer to the output buffer that will be populated by the
 * function
 * \param[in/out] outlen Holds the length of the output buffer and is populated
 * with the length of the encoded data by this function. The required length
 * of the buffer can be obtained using base64encode_len().
 *
 * \return -1 on failure
 * \return 0 on success
 */
int dna_base64encode(const unsigned char * in, int inlen, char * out, int * outlen);

/** RC4 encrypt/decrypt
 */
#define dna_rc4_decrypt dna_rc4_encrypt
int dna_rc4_encrypt(
        unsigned char * dst, unsigned char * src,
        unsigned int len, unsigned char * key, unsigned int * sum);

/*
 *	@brief: RingBuffer
 */
typedef struct
{
    unsigned char*  buffer;
    unsigned int  	size;
    volatile unsigned int  head; /* Read from */
    volatile unsigned int  tail; /* Write to */
} dna_ringbuffer_t;

/*
 *	@brief: This function is initialization for ringbuffer content
 *	@param[_this]:		ringbuffer content
 *	@param[buffer]:		ring data buffer pointer
 *	@param[size]:		ring data buffer size
 *	@return:			0 	- success
 *						-1 	- failed
 */
signed char dna_ringbuffer_init(dna_ringbuffer_t* _this, unsigned char* buffer, unsigned int size);

/*
 *	@brief: This function is de-initialization for ringbuffer content
 *	@param[_this]:		ringbuffer content
 *	@return:			0 	- success
 */
signed char dna_ringbuffer_deinit(dna_ringbuffer_t* _this);

/*
 *	@brief: This function get ring buffer free size
 *	@param[_this]:		ringbuffer content
 *	@return:			free size
 */
unsigned int dna_ringbuffer_free_space(dna_ringbuffer_t* _this);

/*
 *	@brief: This function get ring buffer used size
 *	@param[_this]:		ringbuffer content
 *	@return:			used size
 */
unsigned int dna_ringbuffer_used_space(dna_ringbuffer_t* _this);

/*
 *	@brief: This function get ring buffer data pointer
 *	@param[_this]:		ringbuffer content
 *	@param[data]:		get the getting data pointer
 *	@param[contiguous_bytes]:	getting data size which can be get
 *	@return:			0	- success
 */
signed char dna_ringbuffer_get_data(dna_ringbuffer_t* _this, unsigned char** data, unsigned int* contiguous_bytes);

/*
 *	@brief: This function consume ring buffer size
 *	@param[_this]:		ringbuffer content
 *	@param[bytes_consumed]:		consume the data size
 *	@rteturn:			0	- success
 */
signed char dna_ringbuffer_consume(dna_ringbuffer_t* _this, unsigned int bytes_consumed);

/*
 *	@brief: This function write data to ring buffer
 *	@param[_this]:		ringbuffer content
 *	@param[data]:		writing data pointer
 *	@param[data_length]:		write data size
 *	@return:			amount of copy size
 */
signed int dna_ringbuffer_write(dna_ringbuffer_t* _this, const unsigned char* data, unsigned int data_length);

/*
 *	@brief:	This function get the full flag
 *	@param[_this]:		ringbuffer content
 *	@return:			0 	- not full
 *						1	- full
 */
unsigned char dna_ringbuffer_is_full(dna_ringbuffer_t *_this);

/*
 *	@brief:	This function reset ringbuffer content
 *	@param[_this]:		ringbuffer content
 *	@return:			0	- success
 *						1	- failed
 */
signed char dna_ringbuffer_reset(dna_ringbuffer_t *_this);

void dna_ringbuffer_dump(dna_ringbuffer_t *_this, unsigned int head, unsigned int tail);
void dna_ringbuffer_info(dna_ringbuffer_t *_this);


#if defined(PC32) || defined(PC64)
#include <pthread.h>
#else
#include "dna_os.h"
#endif

/*!
 *  @brief: Type for Bip buffer.
 */
typedef struct
{
   	// Continous data partition A size.
    unsigned int 	partitionASize;   
    // Continous data partition A start index.
    unsigned int   	partitionAIndex;    
    // Continous data partition B size.
    unsigned int  	partitionBSize;     
    // Continous data partition B start index.
    unsigned int  	partitionBIndex;    
    // Reserved data block size.
    // @todo   do we need nested reserve support for simultanous usage?
    unsigned int  	reservedSize;   
    // Reserved data block start index.
    unsigned int  	reservedIndex;
    // mutex lock
#if defined(PC32) || defined(PC64)
    pthread_mutex_t bip_mutex;
#else
    dna_mutex_handle_t bip_mutex;
#endif
    // Size of the usable buffer area.
    // memorySize
    unsigned int   	bufferSize;
    // Pointer to usable buffer base address.
    // memoryBaseAddress
    char    		buffer[0];
} dna_bipbuffer_t;

int  dna_bipbuffer_construct(dna_bipbuffer_t* _this, unsigned int size);
void dna_bipbuffer_destroy(dna_bipbuffer_t* _this);
void* dna_bipbuffer_reserve(dna_bipbuffer_t* _this, unsigned int size);
void dna_bipbuffer_commit(dna_bipbuffer_t* _this, unsigned int size);
void* dna_bipbuffer_get(dna_bipbuffer_t* _this, unsigned int* countinousBlockSizePtr);
void dna_bipbuffer_decommit(dna_bipbuffer_t* _this, unsigned int size);
unsigned int dna_bipbuffer_usedsize(dna_bipbuffer_t* _this);


#endif

